Repository navigation
Conversation
58c5263 to
1dd21ce
Compare
1dd21ce to
fc42158
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
5 open issues
The Teensy vendor requests implement arbitrary memory read/write over USB control transfers… · Newi2s_audioallocates its private data withSOF_MEM_FLAG_USER. This component is registered as… · New The TX priming loop ignores the return value ofi2s_write(). In Zephyr's I2S API, on write… · New Ifi2s_read()returns a non-NULLrx_blockbutrx_sizeis smaller thanI2S_BLOCK_SIZE(or if… · Newring.countis modified underk_spin_lock(&ring->lock)in other functions, but here it is read… · New
What changed in this PR
This draft PR adds Zephyr-only SOF support for Nordic nRF54L series boards, including new platform bring-up pieces, static pipeline topologies, and new host-like components for USB/I2S/BT audio bridging.
Changes:
- Added Nordic platform layer (clock init, mailbox definitions, platform init) and board-specific static pipeline topologies for nRF54L15 and nRF54LM20.
- Introduced new “host endpoint” style audio components:
usb_audio,i2s_audio,bt_audioplus a Bluetooth service helper and a Nordic-focused static pipeline controller. - Expanded Zephyr build integration (CMake/Kconfig/syscall guards), UUID registry entries, and minor runtime fixes in existing modules/DAI code.
| File | Description |
|---|---|
| zephyr/lib/alloc.c | Adds Nordic heap sizing/allocation path for Zephyr builds. |
| zephyr/include/sof/lib/cpu.h | Gates syscall declarations on CONFIG_USERSPACE for full Zephyr app builds. |
| zephyr/include/rtos/cache.h | Adjusts default cache line size logic to include Nordic. |
| zephyr/CMakeLists.txt | Adds Nordic platform selection/build wiring and generated include dir. |
| uuid-registry.txt | Adds UUID registry entries for new audio components. |
| src/platform/nordic/platform.c | Implements Nordic platform init + IPC/mailbox boot-ready handling. |
| src/platform/nordic/nrf54lm20_pipeline_def.c | Adds static topology for LM20 (USB↔I2S + capture loop). |
| src/platform/nordic/nrf54l15_pipeline_def.c | Adds static topology for L15 full-duplex I2S echo. |
| src/platform/nordic/lib/clk.c | Adds minimal clock table/init for Nordic. |
| src/platform/nordic/include/platform/trace/trace.h | Adds Nordic platform trace header stub. |
| src/platform/nordic/include/platform/platform.h | Adds Nordic platform constants and limits. |
| src/platform/nordic/include/platform/lib/pm_runtime.h | Adds Nordic PM runtime header stub. |
| src/platform/nordic/include/platform/lib/memory.h | Adds Nordic heap sizing + cache alignment macros. |
| src/platform/nordic/include/platform/lib/mailbox.h | Adds mailbox layout and stubbed SW reg accessors. |
| src/platform/nordic/include/platform/lib/dma.h | Adds Nordic DMA header stub (0 DMACs). |
| src/platform/nordic/include/platform/lib/dai.h | Adds Nordic DAI header including Zephyr DAI glue. |
| src/platform/nordic/include/platform/lib/clk.h | Adds Nordic clock constants + init prototype. |
| src/platform/nordic/include/platform/drivers/interrupt.h | Adds Nordic interrupt header stub. |
| src/platform/Kconfig | Adds PLATFORM_NORDIC + nRF54L15/nRF54LM20 choice. |
| src/include/user/debug_stream_slot.h | Adds non-userspace fallback mapping for syscall symbol. |
| src/include/sof/schedule/ll_schedule_domain.h | Gates syscall API on CONFIG_USERSPACE for full Zephyr app. |
| src/include/sof/schedule/dp_schedule.h | Adds non-userspace fallbacks and gates syscalls on CONFIG_USERSPACE. |
| src/include/sof/lib_manager.h | Gates syscall API on CONFIG_USERSPACE for full Zephyr app. |
| src/include/sof/lib/vregion.h | Only includes Zephyr syscall header when userspace is enabled. |
| src/include/sof/lib/dai-zephyr.h | Adds non-userspace fallbacks for Zephyr DAI device accessors. |
| src/include/sof/ipc/msg.h | Gates IPC-related syscalls on CONFIG_USERSPACE for full Zephyr app. |
| src/include/sof/ipc/ipc_reply.h | Gates reply syscall on CONFIG_USERSPACE for full Zephyr app. |
| src/include/sof/audio/usb_audio.h | Adds public header for USB audio component bridge API. |
| src/include/sof/audio/pipeline/sof_static_pipeline.h | Adds higher-level static pipeline control/status API. |
| src/include/sof/audio/module_adapter/module/generic.h | Gates module syscalls on CONFIG_USERSPACE in full Zephyr app. |
| src/include/sof/audio/i2s_audio.h | Adds public header for I2S audio component stats API. |
| src/include/sof/audio/bt_service.h | Adds public BT service control/status API. |
| src/include/sof/audio/bt_audio.h | Adds public BT audio component bridge API. |
| src/include/ipc4/notification.h | Gates IPC4 notification syscalls on CONFIG_USERSPACE. |
| src/include/ipc4/handler.h | Gates IPC4 handler syscalls on CONFIG_USERSPACE. |
| src/audio/usb_audio.c | Implements USB audio ring-buffer bridge component (usb_audio). |
| src/audio/pipeline/sof_static_pipeline.c | Adds Nordic-focused static pipeline orchestration + UAC2 glue. |
| src/audio/pipeline/CMakeLists.txt | Builds sof_static_pipeline.c for Nordic. |
| src/audio/module_adapter/module_adapter_ipc4.c | Initializes module sinks/sources if missing before prepare. |
| src/audio/i2s_audio.c | Implements Zephyr I2S bridge component (i2s_audio). |
| src/audio/drc/drc_riscv.c | Switches byte count/channel parameter types to size_t/unsigned. |
| src/audio/drc/drc_log.c | Forces DRC module registration reference when built-in. |
| src/audio/drc/drc_arm.c | Switches byte count/channel parameter types to size_t/unsigned. |
| src/audio/dai-zephyr.c | Nordic-specific DAI reset/trigger behavior adjustments. |
| src/audio/bt_service.c | Adds BT service thread + Nordic LM20/L15 connect/scan logic. |
| src/audio/bt_audio.c | Implements BT audio ring-buffer bridge component (bt_audio). |
| src/audio/Kconfig | Adds Kconfigs for new USB/BT/I2S bridge components. |
| src/audio/CMakeLists.txt | Adds build rules for new audio components. |
| scripts/cmake/misc.cmake | Treats full Zephyr app builds as “Zephyr” in helper macro. |
| app/src/usbd_init.c | Adds USB device stack init helper (with Teensy vendor requests). |
| app/src/sample_usbd.h | Adds sample USBD helper header. |
| app/src/main.c | Initializes UAC2 ops, USB stack, BT service, and static pipelines for Nordic. |
| app/boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay | Adds LM20 UAC2 + TDM pinmux overlay and alias for I2S node. |
| app/boards/nrf54lm20dk_nrf54lm20b_cpuapp.conf | Adds LM20 feature set config (UAC2 HS, TDM, modules). |
| app/boards/nrf54l15dk_nrf54l15_cpuapp.overlay | Adds L15 I2S20 pinmux overlay and alias for I2S node. |
| app/boards/nrf54l15dk_nrf54l15_cpuapp.conf | Adds L15 feature set config (I2S NRFX slave, modules). |
| app/Kconfig | Pulls in sample USBD Kconfig and rsource Zephyr Kconfig when needed. |
| app/CMakeLists.txt | Links SOF libraries into the Zephyr app and adds USBD init source. |
| Kconfig.sof | Always includes Zephyr log Kconfig rather than gating on module build. |
Review effort: Lite
| static struct net_buf *teensy_peek_to_host(const struct usbd_context *const ctx, | ||
| const struct usb_setup_packet *const setup) | ||
| { | ||
| uint32_t addr = (setup->wIndex << 16) | setup->wValue; | ||
| uint16_t len = MIN(setup->wLength, 64); | ||
| if (!len) return NULL; | ||
| struct net_buf *buf = usbd_ep_ctrl_data_in_alloc(ctx, len); | ||
| if (!buf) return NULL; | ||
| net_buf_add_mem(buf, (const void *)addr, len); | ||
| return buf; | ||
| } | ||
|
|
||
| static int teensy_poke_to_dev(const struct usbd_context *const ctx, | ||
| const struct usb_setup_packet *const setup, | ||
| const struct net_buf *const buf) | ||
| { | ||
| ARG_UNUSED(ctx); | ||
| uint32_t addr = (setup->wIndex << 16) | setup->wValue; | ||
| if (buf && buf->len > 0) { | ||
| if (setup->wLength == 1) { | ||
| *(volatile uint8_t *)addr = buf->data[0]; | ||
| } else if (setup->wLength == 2) { | ||
| uint16_t val; | ||
| memcpy(&val, buf->data, 2); | ||
| *(volatile uint16_t *)addr = val; | ||
| } else if (setup->wLength == 4) { | ||
| uint32_t val; | ||
| memcpy(&val, buf->data, 4); | ||
| *(volatile uint32_t *)addr = val; | ||
| } | ||
| } | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Removed all Teensy and ESP32 vendor requests, peek/poke routines, and hardware diagnostics entirely from usbd_init.c, eliminating arbitrary memory access risks and keeping the USB stack standard.
|
|
||
| dev->ipc_config = *config; | ||
|
|
||
| iad = rzalloc(SOF_MEM_FLAG_USER, sizeof(*iad)); |
There was a problem hiding this comment.
Fixed to allocate with SOF_MEM_FLAG_KERNEL consistent with kernel context and other host components.
| void *block; | ||
| for (int i = 0; i < 8; i++) { | ||
| if (k_mem_slab_alloc(&i2s_tx_slab, &block, K_NO_WAIT) == 0) { | ||
| memset(block, 0, I2S_BLOCK_SIZE); | ||
| i2s_write(s_i2s_dev, block, I2S_BLOCK_SIZE); | ||
| } | ||
| } |
There was a problem hiding this comment.
Fixed: now checks i2s_write() return value during TX priming and frees the slab buffer on write failure to prevent memory leaks.
| } | ||
| k_mem_slab_free(&i2s_rx_slab, rx_block); | ||
| s_i2s_stats.rx_frames += frames_to_copy; | ||
| } else { |
There was a problem hiding this comment.
Fixed: ensures rx_block is released back to i2s_rx_slab on all error and size-mismatch paths.
| if (!g_capture_data || !g_capture_data->active || !g_capture_data->started) { | ||
| return false; | ||
| } | ||
| return g_capture_data->ring.count >= bytes; |
There was a problem hiding this comment.
Fixed: usb_audio_has_capture_data() now acquires ring->lock before inspecting ring->count to prevent race conditions on SMP/preemption.
lgirdwood
left a comment
There was a problem hiding this comment.
This needs to be split into zephyr patches and sof patches. Each per feature. The zephyr patches can go on my fork and be referred via a temp west patch
| const struct sof_drc_params *p, | ||
| int nbyte, | ||
| int nch) | ||
| size_t nbyte, |
There was a problem hiding this comment.
this needs to be a separate patch
There was a problem hiding this comment.
Split into a dedicated commit: audio: drc: align drc_arm and drc_riscv parameter types with drc_algorithm.h.
| EXPORT_SYMBOL(log_dynamic_drc); | ||
| #endif | ||
|
|
||
| #if !CONFIG_COMP_DRC_MODULE |
There was a problem hiding this comment.
Reverted this change; the __used reference was a temporary workaround that broke non-Zephyr host testbench builds. DRC symbols are properly linked without it.
| { | ||
| struct processing_module *mod = comp_mod(dev); | ||
|
|
||
| if (!mod->num_of_sources && !mod->num_of_sinks) |
There was a problem hiding this comment.
should be its own patch
There was a problem hiding this comment.
Split into a dedicated commit: audio: module_adapter: initialize sinks and sources in prepare if unpopulated.
| @@ -0,0 +1,805 @@ | |||
| // SPDX-License-Identifier: BSD-3-Clause | |||
There was a problem hiding this comment.
we should be reusing the existing static pipeline logic.
There was a problem hiding this comment.
Refactored to directly reuse the upstream static_pipeline_loader.c and static_pipeline_uac2.c infrastructure (sof_static_topology_init, sof_static_pipeline_trigger, sof_static_kcontrol_set_by_uac2, etc.). Purged all non-Nordic (ESP32-P4 and Teensy 4.1) hardware manipulation and register code.
|
|
||
| if (g_status.playback_active || g_status.capture_active) { | ||
| s_sof_diag_cnt++; | ||
| #if defined(CONFIG_PLATFORM_ESP32P4) |
There was a problem hiding this comment.
this looks like it should be under LOG_DBG ?
There was a problem hiding this comment.
Fixed: replaced periodic diagnostics with LOG_DBG and removed the ESP32 register dump entirely.
…rithm.h Update drc_update_detector_average and drc_compress_output in drc_arm.c and drc_riscv.c to take size_t nbyte and unsigned int nch, matching the prototypes declared in drc_algorithm.h. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…opulated In static audio pipeline configurations where module sources and sinks have not yet been enumerated via dynamic IPC4 binding commands, trigger module_adapter_update_sinks_sources() during module_adapter_sink_src_prepare() if both num_of_sources and num_of_sinks are zero. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ication support - Guard Zephyr syscall headers and prototypes with CONFIG_USERSPACE checks in SOF headers so non-userspace platforms build without stub generation. - Fix Doxygen group closing tag in dai-zephyr.h to ensure valid group scope independent of CONFIG_USERSPACE definition. - Support CONFIG_SOF_FULL_ZEPHYR_APPLICATION in is_zephyr() macro. - Hoist version and uuid registry target generation before subdirectory processing. - Add UUID entries for usb_audio and bt_audio in uuid-registry.txt. - Define heapmem sizing for CONFIG_PLATFORM_NORDIC. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Temporarily point the Zephyr project remote to https://github.com/lgirdwood/zephyr at revision fcf26c58845d3cf24348d273e119879a699e4fc9 (branch feature/nordic-dai-port) which contains the i2s_nrfx and i2s_nrf_tdm DAI driver enhancements for Nordic nRF54L Series boards while upstream Zephyr PR reviews are pending. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Add USB Audio Class 2 (UAC2) host endpoint component (usb_audio.c) with spinlock-protected buffer count checking. - Add Bluetooth LE Audio streaming endpoint and service (bt_audio.c, bt_service.c). - Add Zephyr I2S host endpoint supporting full-duplex PCM streaming (i2s_audio.c), allocating private context with SOF_MEM_FLAG_KERNEL, error handling on TX priming buffer submission with slab release, and RX slab free on error/mismatch. - Add static pipeline runner and runtime control dispatcher (sof_static_pipeline.c) reusing upstream static pipeline topology and UAC2 kcontrol APIs. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…l-duplex I2S loopback
Add full platform support and static audio topologies for Nordic nRF54L15
(PCA10156) and nRF54LM20 (PCA10184) running on Zephyr RTOS:
- src/platform/nordic: platform boot, clock tree (128 MHz), mailbox structures,
Zephyr timer-based Low-Latency scheduler domain (zephyr_domain_init).
- static topologies:
* nRF54LM20: Pipeline 1 (USB_PB -> VOL -> EQ -> DRC -> I2S_TX) master playback,
Pipeline 2 (I2S_RX -> LEVEL -> USB_CAP) master loopback capture.
* nRF54L15: Pipeline 1 (I2S_RX -> VOL -> EQ -> DRC -> I2S_TX) slave full-duplex echo.
- app/boards: devicetree overlays and Kconfig configurations for:
* nrf54l15dk_nrf54l15_cpuapp: i2s20 slave interconnect mapped to Port 1
(P1.11 BCLK, P1.12 LRCK, P1.09 SDIN, P1.08 SDOUT).
* nrf54lm20dk_nrf54lm20b_cpuapp: High-speed USB UAC2 device and i2s_nrf_tdm
master (P1.23 BCLK, P1.24 FSYNC, P1.30 SDOUT, P1.31 SDIN).
- app/src/usbd_init.c: Standard USB UAC2 device stack initialization without
non-standard peek/poke vendor requests.
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
fc42158 to
f583f24
Compare
|
The PR has been reorganized according to review feedback:
|


Summary
This draft PR introduces Sound Open Firmware (SOF) platform support for Nordic Semiconductor nRF54L Series development boards (ARM Cortex-M33 with FPU @ 128 MHz):
PCA10184): High-speed USB UAC2 ingress and hardware I2S/TDM Master Tx/Rx.PCA10156): Hardware I2S20 Slave Full-Duplex Echo with parametric EQ and DRC processing.Companion Zephyr driver changes are in lgirdwood/zephyr#2 on branch
feature/nordic-dai-port.Key Changes
Nordic Platform Support (
src/platform/nordic/):nrf54l15dk_nrf54l15_cpuappandnrf54lm20dk_nrf54lm20b_cpuapp.I2S Hardware Audio Driver Component (
src/audio/i2s_audio.c):i2s_nrfx(nRF54L15) andi2s_nrf_tdm(nRF54LM20).Static Audio Pipeline Topologies:
nrf54lm20_pipeline_def.c):USB_PBVOL_PBEQ_PBDRC_PBI2S_TX(TDM Master Tx)I2S_RX(TDM Master Rx)LEVEL_RXUSB_CAPnrf54l15_pipeline_def.c):I2S_RX(I2S20 Slave Rx)VOL_PBEQ_PBDRC_PBI2S_TX(I2S20 Slave Tx) full-duplex loopback.nRF54L15 Interconnect Pin Multiplexing:
i2s20peripheral to GPIO Port 1 pins (P1.11SCK,P1.12LRCK,P1.09SDIN,P1.08SDOUT) to comply with nRF54L15 peripheral domain interconnect silicon constraints.Static Pipeline Loader (
static_pipeline_loader.c):sof_static_pipeline_trigger()to resolvepipe->sink_compwhen triggering capture pipelines where scheduler component is not at the source.Live Hardware Verification
Verified with physical jumper cables between nRF54LM20-DK Header P3 (Master) and nRF54L15-DK Header P1 (Slave):
P1.23P1.11P1.24P1.12P1.30P1.09P1.31P1.08Both boards continuously stream full-duplex 48 kHz stereo 16-bit PCM at exactly 48,000 frames/second with 0 overruns: